package test.http;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.util.AsciiString;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.FastThreadLocal;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import static io.netty.handler.codec.http.HttpHeaderNames.*;
import static io.netty.handler.codec.http.HttpHeaderValues.TEXT_PLAIN;
import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;

public class PlainTextHandler extends ChannelInboundHandlerAdapter {

    private static final FastThreadLocal<DateFormat> FORMAT = new FastThreadLocal<>() {
        @Override
        protected DateFormat initialValue() {
            return new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z");
        }
    };

    private static final CharSequence SERVER_NAME = AsciiString.cached("Netty");

    private volatile CharSequence date = new AsciiString(FORMAT.get().format(new Date()));

//    PlainTextHandler(ScheduledExecutorService service) {
//        service.scheduleWithFixedDelay(new Runnable() {
//            private final DateFormat format = FORMAT.get();
//
//            @Override
//            public void run() {
//                date = new AsciiString(format.format(new Date()));
//            }
//        }, 1000, 1000, TimeUnit.MILLISECONDS);
//    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof HttpRequest) {
            try {
                HttpRequest request = (HttpRequest) msg;
                process(ctx, request);
            } finally {
                ReferenceCountUtil.release(msg);
            }
        }
    }

    private void process(ChannelHandlerContext ctx, HttpRequest request) throws Exception {
        String uri = request.uri();
        FullHttpResponse response;
        if ("/plain-text".equals(uri)) {
//            System.out.println("request header -> " + request.headers());
            byte[] STATIC_PLAINTEXT = "Plain Text".getBytes(CharsetUtil.UTF_8);
            int STATIC_PLAINTEXT_LEN = STATIC_PLAINTEXT.length;
            CharSequence PLAINTEXT_CLHEADER_VALUE = AsciiString.cached(String.valueOf(STATIC_PLAINTEXT_LEN));
            ByteBuf buf = Unpooled.wrappedBuffer(STATIC_PLAINTEXT);
            response = makeResponse(buf, TEXT_PLAIN, PLAINTEXT_CLHEADER_VALUE);
        } else {
            response = new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND, Unpooled.EMPTY_BUFFER, false);
        }
//        System.out.println("processed, response: " + response);
        ctx.write(response);//
    }

    private FullHttpResponse makeResponse(ByteBuf buf, CharSequence contentType, CharSequence contentLength) {
        final FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, buf, false);
        response.headers()
                .set(CONTENT_TYPE, contentType)
                .set(SERVER, SERVER_NAME)
                .set(DATE, date)
                .set(CONTENT_LENGTH, contentLength);
        return response;
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }
}

